package com.tinyseed.emcp.api.basicdata.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.tinyseed.emcp.api.app.common.Constant;
import com.tinyseed.emcp.api.app.config.DataSourceKey;
import com.tinyseed.emcp.api.app.config.TargetDataSource;
import com.tinyseed.emcp.api.basicdata.domain.*;
import com.tinyseed.emcp.api.basicdata.model.*;
import com.tinyseed.emcp.api.basicdata.repository.*;
import com.tinyseed.hmxx.common.utils.QueryHelp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/***
 * @ClassName: EnterpriseMonitorServiceImpl
 * @Description: 企业监控
 * @Auther: Harlan.Xiong
 * @Date: 2019-12-27 15:11
 * @version : V1.0
 */
@Service
public class EnterpriseMonitorServiceImpl implements EnterpriseMonitorService {
    @Autowired
    private EnterpriseRepository enterpriseRepository;
    @Autowired
    private WorkshopRepository workshopRepository;
    @Autowired
    private MonitorRepository monitorRepository;
    @Autowired
    private MonitorRstDataLatestRepository monitorRstDataLatestRepository;
    @Autowired
    private ProducePolluteRepository producePolluteRepository;
    @Autowired
    private MonitorRstDataRepository monitorRstDataRepository;

    @Override
    public List<EnterpriseMonitorNodeOutputDTO> getTree(Long id) {
        // 读取层次数据结果集列表
        List<EnterpriseMonitorNodeOutputDTO> nodes = null;
        List dataList = new ArrayList();
        Enterprise enterprise = enterpriseRepository.getById(id);
        if (null != enterprise) {
            HashMap dataRecord = new HashMap();
            dataRecord.put("id", enterprise.getId());
            dataRecord.put("name", enterprise.getEnterpriseName());
            dataRecord.put("pid", "");
            dataRecord.put("type", Constant.TREE_NODE_ENTERPRISE);
            dataList.add(dataRecord);
            List<Workshop> workshops = workshopRepository.findAllByEnterpriseId(enterprise.getId());
            if (!CollectionUtils.isEmpty(workshops)) {
                workshops.forEach(workshop -> {
                    HashMap dataRecord2 = new HashMap();
                    dataRecord2.put("id", Constant.WORKSHOP_ID_REFIX + workshop.getId());
                    dataRecord2.put("name", workshop.getShopName());
                    dataRecord2.put("pid", workshop.getEnterpriseId());
                    dataRecord2.put("type", Constant.TREE_NODE_WORKSHOP);
                    dataList.add(dataRecord2);
                    HashMap dataRecord3 = new HashMap();
                    dataRecord3.put("id", Constant.MONITOR_PRODUCE_TREE_ID + workshop.getId());
                    dataRecord3.put("name", Constant.MONITOR_PRODUCE_TREE_NAME);
                    dataRecord3.put("pid", Constant.WORKSHOP_ID_REFIX + workshop.getId());
                    dataRecord3.put("type", -1);
                    dataList.add(dataRecord3);
                    HashMap dataRecord4 = new HashMap();
                    dataRecord4.put("id", Constant.MONITOR_POLLUTION_TREE_ID + workshop.getId());
                    dataRecord4.put("name", Constant.MONITOR_POLLUTION_TREE_NAME);
                    dataRecord4.put("pid", Constant.WORKSHOP_ID_REFIX + workshop.getId());
                    dataRecord4.put("type", -1);
                    dataList.add(dataRecord4);
                    List<Monitor> monitors = monitorRepository.findByShopId(workshop.getId());
                    if (!CollectionUtils.isEmpty(monitors)) {
                        monitors.forEach(monitor -> {
                            HashMap dataRecord5 = new HashMap();
                            String pid = null;
                            if (Constant.MONITOR_PRODUCE_TYPE.equals(monitor.getEquipmentType())) {
                                pid = Constant.MONITOR_PRODUCE_TREE_ID + monitor.getShopId();
                            } else {
                                pid = Constant.MONITOR_POLLUTION_TREE_ID + monitor.getShopId();
                            }

                            dataRecord5.put("id", Constant.MONITOR_PRODUCE_POLLUTION_ID_REFIX + monitor.getId());
                            dataRecord5.put("name", monitor.getMonitorName());
                            dataRecord5.put("pid", pid);
                            dataRecord5.put("type", Constant.TREE_NODE_MONITOR);
                            dataList.add(dataRecord5);
                        });

                    }
                });
            }
            // 节点列表（散列表，用于临时存储节点对象）
            HashMap nodeMap = new HashMap();
            // 根节点集合
            nodes = Lists.newArrayList();
            // 根据结果集构造节点列表（存入散列表）
            for (Iterator it = dataList.iterator(); it.hasNext(); ) {
                Map dataRecord4 = (Map) it.next();
                EnterpriseMonitorNodeOutputDTO node = new EnterpriseMonitorNodeOutputDTO();
                node.setId(dataRecord4.get("id").toString());
                node.setName(dataRecord4.get("name").toString());
                if (dataRecord4.get("pid") == null || dataRecord4.get("pid").equals("") || dataRecord4.get("pid").equals("null")) {
                    node.setPid(null);
                } else {
                    node.setPid(dataRecord4.get("pid").toString());
                }
                node.setType(dataRecord4.get("type").toString());
                nodeMap.put(node.getId(), node);
            }

            // 构造无序的多叉树
            Set entrySet = nodeMap.entrySet();
            for (Object o : entrySet) {
                EnterpriseMonitorNodeOutputDTO node = (EnterpriseMonitorNodeOutputDTO) ((Map.Entry) o).getValue();
                if (node.getPid() == null || node.getPid().equals("") || node.getPid().equals("null")) {
                    nodes.add(node);
                } else {
                    ((EnterpriseMonitorNodeOutputDTO) nodeMap.get(node.getPid())).addChild(node);
                }
            }

        }

        return nodes;
    }

    @Override
    public Page findAll(EnterpriseInputDTO enterpriseInputDTO, int size, int current) {
        EnterpriseMonitorInputDTO dict = new EnterpriseMonitorInputDTO();
        if (null != enterpriseInputDTO && null != enterpriseInputDTO.getId()) {
            List<Workshop> workshops = workshopRepository.findAllByEnterpriseId(enterpriseInputDTO.getId());
            if (!CollectionUtils.isEmpty(workshops)) {
                List<Long> shopIds = Lists.newArrayList();
                workshops.forEach(d -> {
                    shopIds.add(d.getId());
                });
                dict.setShopIds(shopIds);
            }
        }

        Pageable pageable = PageRequest.of(current, size);
        Page page = monitorRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, dict, criteriaBuilder), pageable);
        return page;
    }

    @Override
    public MonitorRstDataLatestOutputDTO getDeviceDataLatest(String id) {
        MonitorRstDataLatestOutputDTO monitorRstDataLatestOutputDTO = null;
        Long deviceId = getDeviceId(id);
        Monitor monitor = monitorRepository.getById(deviceId);
        if (null != monitor) {
            MonitorRstDataLatest monitorRstDataLatest = monitorRstDataLatestRepository.findBySwitchSnAndDeviceSn(monitor.getSwitchSn(), monitor.getInstrumentAddress());
            if (null != monitorRstDataLatest) {
                monitorRstDataLatestOutputDTO = new MonitorRstDataLatestOutputDTO();
                BeanUtil.copyProperties(monitorRstDataLatest, monitorRstDataLatestOutputDTO);
            }
        }
        return monitorRstDataLatestOutputDTO;
    }

    @Override
    public List<MonitorRstDataChartOutputDTO> queryDeviceDataListChart(String id, Date dateTime) {
        //时间格式化
        List<ProducePollute> producePollutes = null;
        if (dateTime == null) {
            dateTime = new Date();
        }

        StopWatch stopWatch = new StopWatch();
        stopWatch.start("查询设备id");
        Long deviceId = getDeviceId(id);
        stopWatch.stop();


        stopWatch.start("查询监测点id");
        Monitor monitor = monitorRepository.getById(deviceId);
        stopWatch.stop();


        List<Long> ids = Lists.newArrayList();

        stopWatch.start("查找产污治污对应关系");
        if (null != monitor) {
            ids.add(deviceId);
            if (Constant.MONITOR_PRODUCE_TYPE.equals(monitor.getEquipmentType())) {
                //查找产污治污对应关系
                producePollutes = producePolluteRepository.findAllByProduceId(deviceId);
                if (!CollectionUtils.isEmpty(producePollutes)) {
                    List<Long> polluteIds = producePollutes.stream().map(ProducePollute::getPolluteId).collect(Collectors.toList());
                    ids.addAll(polluteIds);
                }

            } else {
                producePollutes = producePolluteRepository.findAllByPolluteId(deviceId);
                if (!CollectionUtils.isEmpty(producePollutes)) {
                    List<Long> produceIds = producePollutes.stream().map(ProducePollute::getProduceId).collect(Collectors.toList());
                    ids.addAll(produceIds);

                }
            }
        }
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());

        return copyList(ids, dateTime);
    }

    @Override
    public EnterpriseMonitorOutputDTO getEnterpriseMonitorInfo(Long id) {
        EnterpriseMonitorOutputDTO enterpriseMonitorOutputDTO = null;
        Enterprise enterprise = enterpriseRepository.getById(id);
        long produceTotal = 0L;
        long pollutionTotal = 0L;


        if (null != enterprise) {
            enterpriseMonitorOutputDTO = new EnterpriseMonitorOutputDTO();
            List<Workshop> workshops = workshopRepository.findAllByEnterpriseId(enterprise.getId());
            for (Workshop workshop : workshops) {
                int produceCount = monitorRepository.countByShopIdAndEquipmentType(workshop.getId(), Constant.MONITOR_PRODUCE_TYPE);
                int pollutionCount = monitorRepository.countByShopIdAndEquipmentType(workshop.getId(), Constant.MONITOR_POLLUTION_TYPE);
                produceTotal = produceTotal + produceCount;
                pollutionTotal = pollutionTotal + pollutionCount;
            }
            BeanUtil.copyProperties(enterprise, enterpriseMonitorOutputDTO);
            enterpriseMonitorOutputDTO.setIndustryName(enterprise.getIndustry().getIndustryName());
            enterpriseMonitorOutputDTO.setProduceDeviceTotal(produceTotal);
            enterpriseMonitorOutputDTO.setPolluteDeviceTotal(pollutionTotal);
        }


        return enterpriseMonitorOutputDTO;
    }

    private List<MonitorRstDataChartOutputDTO> copyList(List<Long> ids, Date dateTime) {


        Timestamp startTime =new Timestamp(DateUtil.beginOfDay(dateTime).getTime());
        Timestamp endTime =new Timestamp(DateUtil.endOfDay(dateTime).getTime());
        List<MonitorRstDataChartOutputDTO> monitorRstDataChartOutputDTOList = Lists.newArrayList();
        List<Monitor> monitors = monitorRepository.findAllById(ids);

        int i = 0;
        for (Monitor m : monitors) {
            i++;
            MonitorRstDataChartOutputDTO monitorRstDataChartOutputDTO = new MonitorRstDataChartOutputDTO();
            List<MonitorRstDataOutputDTO> monitorRstDataList = monitorRstDataRepository.findAllBySwitchSnAndDeviceSnAndBetweenDataTime(m.getSwitchSn(), m.getInstrumentAddress(), startTime,endTime);
            monitorRstDataChartOutputDTO.setMonitorName(m.getMonitorName());
            monitorRstDataChartOutputDTO.setMonitorRstDataList(monitorRstDataList);
            monitorRstDataChartOutputDTOList.add(monitorRstDataChartOutputDTO);

        }
        return monitorRstDataChartOutputDTOList;
    }



    private Long getDeviceId(String id) {
        return Long.valueOf(id.substring(Constant.MONITOR_PRODUCE_POLLUTION_ID_REFIX.length(), id.length()));
    }

}
